package com.xw.echo.core.pool;

import com.xw.echo.core.register.HostAndPort;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 连接池管理类，用于管理多个连接池
 */
public class ManagerConnectPool {
    // 单例模式，保证整个应用只有一个连接池管理器实例
    private static ManagerConnectPool instance = getInstance();

    // 存储每个主机和端口对应的连接池
    private ConcurrentHashMap<String, ConnectPool> map;
    // 存储每个服务器名称对应的主机和端口的连接池映射
    private ConcurrentHashMap<String, Map<String, ConnectPool>> clusterMap;

    // 私有构造方法，防止外部实例化
    private ManagerConnectPool() {
        this.map = new ConcurrentHashMap<>();
        this.clusterMap = new ConcurrentHashMap<>();
    }

    /**
     * 获取连接池管理器的单例实例
     *
     * @return 单例实例
     */
    public static synchronized ManagerConnectPool getInstance() {
        if (instance == null) {
            instance = new ManagerConnectPool();
        }
        return instance;
    }

    /**
     * 将主机和端口与连接池关联
     *
     * @param hostAndPort 主机和端口
     * @param connectPool 连接池
     */
    public void putConnectPool(HostAndPort hostAndPort, ConnectPool connectPool) {
        map.put(hostAndPort.getHost() + ":" + hostAndPort.getPort(), connectPool);
    }

    /**
     * 根据主机和端口获取对应的连接池
     *
     * @param hostAndPort 主机和端口
     * @return 连接池
     */
    public ConnectPool getConnectPool(HostAndPort hostAndPort) {
        return map.get(hostAndPort.getHost() + ":" + hostAndPort.getPort());
    }

    /**
     * 设置服务器名称与连接池的映射
     *
     * @param serverName   服务器名称
     * @param connectPools 连接池映射
     */
    public void setClusterMap(String serverName, Map<String, ConnectPool> connectPools) {
        clusterMap.put(serverName, connectPools);
    }

    /**
     * 根据服务器名称获取连接池映射
     *
     * @param serverName 服务器名称
     * @return 连接池映射
     */
    public Map<String, ConnectPool> getClusterMap(String serverName) {
        return clusterMap.get(serverName);
    }

    /**
     * 初始化单个主机和端口的连接池
     *
     * @param hostAndPort 主机和端口
     */
    public void initConnectionPool(HostAndPort hostAndPort) {
        instance.putConnectPool(hostAndPort, craterConnectPool(hostAndPort));
    }

    /**
     * 初始化服务器集群的连接池
     *
     * @param serverName   服务器名称
     * @param hostAndPorts 主机和端口列表
     */
    public void initClusterConnectionPool(String serverName, List<HostAndPort> hostAndPorts) {
        Map<String, ConnectPool> map = new ConcurrentHashMap<>();
        for (HostAndPort hostAndPort : hostAndPorts) {
            map.put(hostAndPort.getHost() + ":" + hostAndPort.getPort(), craterConnectPool(hostAndPort));
        }
        instance.setClusterMap(serverName, map);
    }

    /**
     * 创建新的连接池
     *
     * @param hostAndPort 主机和端口
     * @return 新的连接池
     */
    private ConnectPool craterConnectPool(HostAndPort hostAndPort) {
        ConnectPool connectPool = new ConnectPool(hostAndPort);
        return connectPool;
    }

    public void replaceConnectPool(List<String> newHostAndPorts, String clusterName) {
        // 获取 clusterName 对应的内层 Map   Map<String, ConnectPool> hostMap = clusterMap.get(clusterName);
        Map<String, ConnectPool> hostMap = clusterMap.get(clusterName);
        if (hostMap!=null) {
            //遍历新的主机名和端口列表
            // 遍历新的主机名和端口列表
            List<String> oldHostAndPorts = new ArrayList<>(hostMap.keySet());
            // 从 newHostAndPorts 中删除
            newHostAndPorts.removeIf(oldHostAndPorts::remove);
            if (!newHostAndPorts.isEmpty()) {
                newHostAndPorts.forEach(newHost -> {
                    HostAndPort newHostAndPort = parseHostAndPort(newHost);
                    ConnectPool newConnectPool = craterConnectPool(newHostAndPort);
                    hostMap.put(newHost, newConnectPool);
                });
            }
            oldHostAndPorts.forEach(oldHost -> {
                ConnectPool connectPool = hostMap.get(oldHost);
                connectPool.shutdown();
                hostMap.remove(oldHost);
            });
        }
    }
    private HostAndPort parseHostAndPort(String hostAndPortStr) {
        if (hostAndPortStr == null || !hostAndPortStr.contains(":")) {
            throw new IllegalArgumentException("Invalid host and port format");
        }
        String[] parts = hostAndPortStr.split(":");
        String host = parts[0];
        int port = Integer.parseInt(parts[1]);

        return new HostAndPort(host, port);
    }

}

